package com.upbos.upm.login;

import cn.hutool.core.util.URLUtil;
import com.upbos.cache.SingleCacheManager;
import com.upbos.core.ret.RetCode;
import com.upbos.core.ret.RetData;
import com.upbos.core.util.CookieUtils;
import com.upbos.core.util.StringPool;
import com.upbos.sso.SsoManager;
import com.upbos.sso.UserContext;
import com.upbos.sso.entity.SsoUser;
import com.upbos.sso.entity.Token;
import com.upbos.upm.common.Constants;
import com.upbos.upm.common.UpmConfiguration;
import com.upbos.upm.listener.UserLoginListener;
import com.upbos.upm.common.PasswordSecureUtil;
import com.upbos.upm.entity.Module;
import com.upbos.upm.entity.Org;
import com.upbos.upm.entity.User;
import com.upbos.upm.enums.UserStatus;
import org.springframework.beans.BeanUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <b>Application name：</b> LoginService.java <br>
 * <b>Application describing： 用户登录、登出以及获取用户菜单、权限服务类</b> <br>
 * <b>Copyright：</b> Copyright &copy; 2018 upbos.com 版权所有。<br>
 * <b>Company：</b> upbos.com <br>
 * <b>Date：</b> 2018年09月26日 23:28 <br>
 * <b>author：</b> <a href="mailto:wangjz@miyzh.com"> wangjz </a> <br>
 * <b>version：</b>V4.1.0 <br>
 */

@Service
public class LoginService {

    @Resource
    private LoginDao loginDao;

    @Resource
    private SingleCacheManager singleCacheManager;

    @Resource
    private UpmConfiguration configuration;

    @Resource
    private ApplicationContext applicationContext;
    /**
     * 登录验证
     *
     * @param user 用户名和口令
     * @return 验证信息
     */
    public RetData login(User user, HttpServletRequest request, HttpServletResponse response, SsoManager ssoMgr) throws Exception {


        RetData retData = new RetData(RetCode.SUCCESS);
        User dUser = loginDao.getUserByLoginName(user.getLoginName());

        String encryptPassword = PasswordSecureUtil.encrypt(user.getPassword());

        // 用戶名不存在或着密码错误
        if (dUser == null || !dUser.getPassword().equals(encryptPassword)) {
            retData.setCode(Integer.valueOf(UserStatus.ERROR.getValue()));
            retData.setMsg(UserStatus.ERROR.getMsg());
            return retData;
        }

        // 用户名登录成功，判断用户状态
        UserStatus userStatus = UserStatus.getUserStatus(dUser.getStatus());

        retData.setCode(Integer.valueOf(userStatus.getValue()));
        retData.setMsg(userStatus.getMsg());


        // 如果用户注销或者冻结，直接返回
        if (!retData.getCode().equals(Integer.valueOf(UserStatus.NORMAl.getValue()))) {
            return retData;
        }



        // 保存当前登录信息
        SsoUser ssoUser = new SsoUser();
        BeanUtils.copyProperties(dUser, ssoUser);


        Org org = loginDao.getOrgById(dUser.getOrgId());
        ssoUser.setOrgName(org.getName());
        //如果用户扩展码为空时，取所属机构代码
        if (dUser.getExtCode() == null || "".equals(dUser.getExtCode())) {
            ssoUser.setExtCode(org.getCode());
        } else {
            ssoUser.setExtCode(dUser.getExtCode());
        }

        // 清除验证码key
        CookieUtils.removeCookie(response, Constants.CACHE_RCODE);

        Token token = ssoMgr.login(request, response, ssoUser);

        // 用户角色
        List<String> roles = loginDao.listUserRole(dUser.getUid());
        ssoMgr.setAttr(token.getId(), com.upbos.sso.Constants.SESSION_CACHE_ROLE_KEY_NAME, roles);

        List<String> resList = new ArrayList<>();
        // 用户功能模块
        List<String> userModules = loginDao.listUserModule(roles);
        for (String module : userModules) {
            if (module != null && !"".equals(module.trim())) {
                resList.add(prefixUrl(module));
            }
        }

        // 用户功能模块对应的资源
        List<String> userModuleRess = loginDao.listUserModuleRes(roles);
        resList.addAll(userModuleRess);
        ssoMgr.setAttr(token.getId(), com.upbos.sso.Constants.SESSION_CACHE_RES_KEY_NAME, resList);

        // 用户权限
        List<String> privileges = loginDao.listUserPrivilege(roles);
        ssoMgr.setAttr(token.getId(), com.upbos.sso.Constants.SESSION_CACHE_PRIVILEGE, privileges);
        retData.setData(token.getId());

        // 登录成功，通知业务系统
        Map<String, UserLoginListener> map = applicationContext.getBeansOfType(UserLoginListener.class);
        UserContext userContext = new UserContext(ssoMgr, request);
        map.forEach((s, userLoginListener) -> userLoginListener.notice(userContext));

        return retData;
    }

    /**
     * 查询用户的功能菜单树
     *
     * @param uid 用户ID
     * @return 功能菜单树
     */
    public List<Module> listUserModuleTree(String uid) {
        // 所有功能模块，先从缓存获取，没有从数据库获取
        List<Module> allModuleList = (List<Module>) singleCacheManager.getCache(configuration.getCacheName()).get(configuration.getCacheModuleKey());
        if (allModuleList == null) {
            allModuleList = loginDao.listAllModule();
            singleCacheManager.getCache(configuration.getCacheName()).set(configuration.getCacheModuleKey(), allModuleList);
        }

        // 用户拥有的功能模块
        List<String> userModuleIdList = loginDao.listUserModuleId(uid);
        List<Module> userModuleList = allModuleList.stream().filter(res -> {
            for (String id : userModuleIdList) {
                if (id.equals(res.getId())) {
                    return true;
                }
            }
            return false;
        }).collect(Collectors.toList());


        List<Module> userParentModuleList = new ArrayList<>();
        for (Module module : userModuleList) {
            findParentModule(allModuleList, module, userParentModuleList);
        }

        userModuleList.addAll(userParentModuleList);
        // 查找上级功能模块，把当前节点插入上级功能模块的孩子列表中
        userModuleList.forEach(module ->
                userModuleList.stream().filter(m -> m.getParentId().equals(module.getId())).forEach(m -> {
                    List<Module> children = module.getChildren() == null ? new ArrayList<>() : module.getChildren();
                    children.add(m);
                    module.setChildren(children);
                })

        );

        // 获取上级功能模块ID为0的功能模块
        List<Module> userModuleTree = userModuleList.stream().filter(module -> module.getParentId().equals(ROOT_MODULE_ID)).collect(Collectors.toList());

        // 对功能模块树进行排序
        sortTree(userModuleTree);

        return userModuleTree;
    }


    private void findParentModule(List<Module> allModule, Module module, List<Module> resultModule) {
        allModule.stream().filter(item -> item.getId().equals(module.getParentId())).forEach(item -> {
            if (!resultModule.contains(item)) {
                resultModule.add(item.clone());
            }
            findParentModule(allModule, item, resultModule);
        });
    }

    /**
     * 对功能模块树进行排序
     *
     * @param menu
     */
    private void sortTree(List<Module> menu) {
        Collections.sort(menu);
        menu.stream().forEach(m -> {
            if (m.getChildren() != null && m.getChildren().size() > 0) {
                sortTree(m.getChildren());
            }
        });
    }

    private String prefixUrl(String url) {
        url = URLUtil.getPath(url);
        if (url.length() == 0) {
            url = "/";
        }
        // 以"/"开头的资源去掉"/"
        if (StringPool.SLASH.equals(url.substring(0, 1))) {
            url = url.substring(1);
        }

        // 去掉"../"、"./"的开头
        url = url.replaceAll("\\.\\./", "").replaceAll("\\./", "");

        return "/**/" + url;
    }

    private static final String ROOT_MODULE_ID = "0";
}


